/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package tpgen.grammar;

import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author shanki
 */
public class Node {
    private Symbol symbol;
    private Context context;
    private List<Node> children = new ArrayList<Node>();
    
    public Node(Symbol symbol, Context context) {
        this.symbol = symbol;
        this.context    = context;
    }

    Symbol getSymbol() {
        return symbol;
    }

    void add(Node node) {
        children.add(node);
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        
        sb.append("(");
        sb.append(symbol.toString());
        
        for (Node child : children) {
            sb.append(child.toString());
        }
        
        sb.append(")");
        return sb.toString();
    }
    
    public String toUserString() {
        StringBuilder sb = new StringBuilder();

        String str = symbol.toUserString();
        sb.append(str);
        if (str.isEmpty() == false) {
            sb.append(" ");
        }
        
        for (Node child : children) {
            sb.append(child.toUserString());
        }
        
        return sb.toString();
    }
    
    public void traverse(NodeVisitor visitor) {
        visitor.visit(symbol);
        
        for(Node child : children) {
            child.traverse(visitor);
        }
    }

    public Node reconstruct(NodeConstructor constructor) {
        
        // aj je noda neterminalny symbol, alt, opt, ...,
        // tak ju mozeme rekonstruovat iba tak, ze zmenime potomkov
        
        if (constructor.reconstruct(symbol)) {
            Node newNode    = new Node(symbol, context);
                        
            newNode.expand();
            
            return newNode;
        } else {
            Node newNode    = new Node(symbol, context);
            
            for (Node child : children) {
                newNode.add(child.reconstruct(constructor));
            }
            
            return newNode;
        }
    }
    
    public void expand() {
        for(Symbol child : symbol.expand(context)) {
            Node node   = new Node(child, context);
            node.expand();

            add(node);
        }
    }
    
    public interface NodeVisitor {
        public void visit(Symbol symbol);
    }
    
    public interface NodeConstructor {
        public boolean reconstruct(Symbol symbol);
    }

}